namespace("jclass.collections")
({
    Dictionary : jClass({
        constructor : function(src) {
            source.shift();
            if (src) { if (typeof(src.push) === 'function') { source = source.concat(src); }}
            this._prototype.typeName = 'Dictionary';
        },
        public : {
            /**
             * Appends the given item to the end of dictinary
             *
             * @param val object
             */
            addItem : function(val) {
                source.push(val);
            },
            /**
             * Inserts the element at the given index
             * @param index number
             * @param val object
             */
            addItemAt : function(index, val) {
                var part1 = source.slice(0, index), part2 = source.slice(index);
                part1[index] = val;
                source = part1.concat(part2);
            },
            /**
             * Removes all instances of item from the dictionary
             * @param val
             */
            removeItem : function(val) {
                do {
                    var index = this.getItemIndex(val);
                    source.splice(index, 1);
                } while (index != -1)
            },
            /**
             * Removes item at given index
             * @param index number
             */
            removeItemAt : function(index) {
                source.splice(index, 1);
            },
            /**
             * Removes all duplicate items from the dictionary
             */
            removeDuplicates : function() {
                var tmp = [];
                for (var i = 0; i < source.length; i++) {
                    if (source.indexOf(source[i], i + 1) == -1) {
                        tmp.push(source[i]);
                    }
                }
                source = tmp;
            },
            /**
             * Works just like getItemIndex but returns a boolean if the item exists in the dictionary
             * @param item object
             * @return boolean
             */
            containsItem : function(item) {
                return this.getItemIndex(item) != -1;
            },
            /**
             * Returns the item at the give index
             * @param index number
             * @return object
             */
            getItemAt : function(index) {
                return source[index];
            },
            /**
             * Returns the index of the given item
             * @param item
             * @return number
             */
            getItemIndex : function(item) {
                for (var i = 0; i < source.length; i++) {
                    if (source[i] == item) {
                        return i;
                    }
                }
                return -1;
            },
            /**
             * Deep search items
             * @param field Object field to match search
             * @param search String or regular expression
             * @return array result set
             */
            findItems : function(field, search) {
                var tmp = [], reg;
                if (arguments.length == 1) { search = field; field = undefined; }
                if (typeof search == 'string') { reg = new RegExp(search, 'ig');
                    } else if (typeof search == 'object') { reg = search; }
                var deepSearch = function(obj, field) {
                    for (var fld in obj) {
                        if (typeof obj[fld] === 'function') { continue; }
                        if (field && field == fld) { if (String(obj[fld]).match(reg)) { return true; } return false;
                        } else if (!field) { if (String(fld).match(reg) || String(obj[fld]).match(reg)) { return true; }
                        } else { if (typeof obj[fld] === 'object') { if (deepSearch(obj[fld], field)) { return true; }}}
                    } return false; };
                for (var i = 0; i < source.length; i++) {
                    if (typeof source[i] === 'object' && deepSearch(source[i], field)) { tmp.push(source[i])
                    } else if (!field && String(source[i]).match(reg)) { tmp.push(source[i]) }
                }
                return tmp;
            },
            /**
             * Remove all elements from the dictionary
             */
            removeAll : function() {
                source = [];
                source.shift();
            },
            /**
             * Merges another instance of Dictionary or othery type of arguments with the dictionary
             *
             * @param arguments Dictionary || Array || objects
             *
             * @usage var x = new Dictionary([1,2]), y = new Dictionary([3,4]), z = [5,6];
             *        x.merge(y);   // 1,2,3,4
             *        x.merge(z);   // 1,2,3,4,5,6
             *        x.merge(7,8); // 1,2,3,4,5,6,7,8
             */
            merge : function() {
                for (var i = 0; i < arguments.length; i++) {
                    var item = arguments[i];
                    if (item === undefined) { source.push(undefined); continue; }
                    if (item.isInstanceOf && item.isInstanceOf(jclass.collections.Dictionary)) {
                        source = source.concat(IE ? item.getSource() : item.source);
                    } else if (typeof(item.push) === 'function') {
                        source = source.concat(item);
                    } else {
                        source.push(item);
                    }
                }
            },
            /**
             * Compacts the dictionary source by removing all undefined and blank objects
             */
            compact : function() {
                var tmp = [];
                for(var i = 0, n = source.length; i < n; i++) {
                    if (source[i] === undefined || source[i] === '' || jUtils.serialize(source[i]).toString() == '{}') { continue; }
                    tmp.push(source[i]);
                }
                source = tmp;
            },
            /**
             * Applies the given function for each element in the dictionary source.
             * The provided function must have one parameter. If any return value is given
             * the return value will replace the element
             *
             * @param fct Function
             */
            forEach : function(fct) {
                for (var i = 0; i < source.length; i++) {
                    var tmp = fct(source[i]);
                    if (tmp) { source[i] = tmp; }
                }
            },
            /**
             * Returns a JSON representation of the dictionary source
             * @return object
             */
            toJSON : function() {
                return jUtils.serialize(source);
            },
            /**
             * Returns a new instance of the Dictionary class
             * @return Dictionary
             */
            clone : function() {
               var x = new jclass.collections.Dictionary();
               x.merge(source);
               return x;
            },
            /**
             * Returns the length of the dictionary source
             * @return Number
             */
            length : Get(function() {
                return source.length;
            }),
            /**
             * Returns a clone dictionary source
             * @return Array
             */
            source : Get(function() {
                return [].concat(source);
            })
        },
        private : {
            source : []
        }
    })
});